home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Honeybee: Hot Shareware
/
Honeybee Hot Shareware (Power Source, Inc.).iso
/
viewer
/
gif.arc
/
NLZW.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-09
|
13KB
|
342 lines
;**************************************************************************
;Written 1/27/88-2/6/88 by Jim Griebel
;Built as a Turbo external OBJ file, this routine replaces READCODE,
;ADDTOPIXEL and all the high-level LZW decoding done by GIFSLOW.
;**************************************************************************
data segment word public
assume ds:data
;definitions for Turbo variables used in this module
extrn clear:byte,interlace:byte,pass:byte
extrn freecode:word,clearcode:word,bitmask:word
extrn width:word,maxcode:word,codesize:word
extrn readmask:word,eofcode:word,height:word
extrn bitsperpixel:byte
extrn linestart:word
extrn nextraster:byte
extrn raster:dword
extrn palette:byte
;And for variables declared locally
bitoffset dw 0
bitoffset2 dw 0
yc dw ?
oldcolor db ?
yoffset dw ?
xoffset dw ?
curcode dw ?
incode dw ?
oldcode dw ?
finchar db ?
rasterseg dw ?
rasterofs dw ?
prefix dw 4096 dup (?)
suffix db 4096 dup (?)
outcode db 1024 dup (?)
scanline db 640 dup (?)
data ends
cseg segment byte public
assume cs:cseg
;We retain some Turbo calls just to keep things simple
extrn doclear:near
extrn moveup:near
public nlzw
nlzw proc near
;Here's where the fun starts. Do the necessary preliminaries, including
;setting constants and variable starting points since Turbo won't let
;us declare them
mov byte ptr oldcolor,255 ;Set oldcolor to a null value
xor ax,ax ;Set bitoffset to start of file
mov bitoffset,ax
mov bitoffset2,ax
mov yoffset,ax ;YOFFSET to origin of screen RAM
mov xoffset,ax ;Ditto for XOFFSET
mov yc,ax ;Zero out Y-coord
;Here's the main loop where the file is decompressed and displayed
top: call readcode ;Extract GIF compression code
push ds
pop es
lea di,outcode ;Aim DI at the output queue
mov bx,bitmask ;Get the bitmask in BX
xor dx,dx ;Zero out DX, used as output counter
cmp ax,eofcode ;Are we at the end of image?
jnz ckclear ;Nope, press on
jmp finis ;Yes, done, exit
ckclear: cmp ax,clearcode ;Did we read a CLEAR code?
jnz noclear ;Nope
inc byte ptr clear ;Yes, turn on the CLEAR flag
push es
push di
push dx
push bx
call doclear ;Reset values to initial
call readcode ;Read raw data
pop bx
pop dx
pop di
pop es
mov oldcode,ax ;Set OLDCODE to value just read
jmp done ;and go put that out
noclear: mov curcode,ax ;Otherwise, check for new data
mov incode,ax
cmp ax,freecode ;See if >= freecode, if so
jl notnew ;Not new, already in table
mov ax,oldcode ;Otherwise curcode=oldcode
mov curcode,ax
mov al,finchar ;stack last char decoded for output
stosb
inc dx ;increment the count
notnew: mov ax,curcode ;Run the hash table for this value
cmp ax,bx ;Current code less than BITMASK?
jle done ;Yes, bail out
loop: mov si,ax
mov al,[si+suffix] ;otherwise stack suffix [curcode]
stosb ;for output
inc dx
shl si,1
mov ax,[si+prefix] ;and set curcode=prefix [curcode]
mov curcode,ax
cmp ax,bx ;If not done, continue
jg loop
done: and ax,bx ;Mask off actual data
mov finchar,al ;Save as FINCHAR
stosb ;And put it on output queue
mov si,di ;Outqueue pointer to SI
dec si ;Back up to valid data
mov cx,dx ;Output count to CX
inc cx ;Make good count for LOOP
push es
std
push ds ;Point ES:DI to SCANLINE
pop es
lea di,scanline
add di,xoffset ;Point into current pos in SCANLINE
mov dx,xoffset ;DX now serves as pos counter
scanloop: lodsb ;get byte from output queue. Stacked
stosb ;LIFO, so deal with it that way
inc di ;overcome auto-decrement
inc di
inc dx ;At end of current scan line?
cmp dx,width
jnz scanloop1 ;Nope, press on
call putout ;Yup, put out the scan line
scanloop1: loop scanloop ;Continue for length of outqueue
mov xoffset,dx ;Save new pos
cld ;Dir flag back to normal
pop es ;ES back to DS
noout: cmp byte ptr clear,0 ;Are we doing a CLEAR?
jz goon ;No, proceed
dec byte ptr clear ;Yes, turn off CLEAR flag
jmp top ;and take the short way out
goon: mov di,freecode ;suffix[freecode]=finchar
mov al,finchar
mov [di+suffix],al
shl di,1 ;Adjust for word-sized array
mov ax,oldcode ;Prefix [freecode]=oldcode
mov [di+prefix],ax
mov ax,incode ;Set Oldcode=Incode
mov oldcode,ax
mov ax,freecode ;Kick to next free code
inc ax
mov freecode,ax
cmp ax,maxcode ;Increase code size if necessary
jge incmax ;(and possible, 12 is limit)
jmp top
incmax: mov ax,maxcode ;maxcode = maxcode * 2
shl ax,1
mov maxcode,ax
mov ax,codesize ;If codesize < 12, increment it
cmp ax,12
jnz inccode
jmp top
inccode: inc ax
mov codesize,ax
mov cl,al ;Compute new READMASK value
xor ch,ch
mov ax,1
shl ax,cl
dec ax
mov readmask,ax
jmp top
finis: ret ;Whole image done, exit
nlzw ENDP
;Put out the array of pixels stored in SCANLINE
putout proc near
push es ;Push sensitive regs
push cx
push ds
push si
cld ;Because caller does STD
mov ax,0a000h ;EGA video segment address
mov es,ax
mov bl,80h ;Current pos in byte
mov bh,oldcolor
mov di,yoffset ;Current Y pos in screen RAM
lea si,scanline
mov dx,3CEH ;DX gets EGA register address
mov cx,width
outloop: lodsb ;Get byte from output queue
cmp al,15
jle outgo
push si
xor ah,ah
mov si,ax
mov al,[si+palette]
pop si
outgo: cmp al,bh ;Same as old color?
jz skipit ;Yes, no need to tell EGA new one
mov bh,al ;Set new color as old color
xchg ah,al
xor al,al ;Index 0
out dx,ax ;Put out both values at once
skipit: mov al,8 ;Now point to mask reg
mov ah,bl
out dx,ax
mov al,es:[di] ;Latch data by read/write memory
stosb
dec di ;compensate for auto-increment
shr bl,1 ;Shift mask to next bit pos
or bl,bl ;Out of mask?
jnz loop1 ;No, skip
mov bl,80H ;Yes, reset mask to top bit
inc di ;DI to next screen byte
loop1: loop outloop ;And keep on
call incyc ;Kick YC and Yoffset to next line
call computey
lea di,scanline ;Point DI back to start of scanline
xor dx,dx ;Pos pointer back to 0
std ;set this back the right (wrong) way
mov oldcolor,bh ;save oldcolor for next time
pop si
pop ds
pop cx
pop es
ret
putout endp
;Compute starting position of this screen line in EGA memory. Just gets
;appropriate value from LINESTART
computey proc near
push ax
push si
mov ax,yc
shl ax,1
lea si,linestart
add si,ax
lodsw
mov yoffset,ax
pop si
pop ax
ret
computey endp
;Increment YC if the picture is non-interlaced, otherwise cope with
;interlace
incyc proc near
mov ax,yc
cmp ax,479 ;Quit if we'll overflow EGA bounds
jnz incit ;otherwise increment
ret
incit: cmp byte ptr interlace,0
jz simple
cmp byte ptr pass,0
jnz in2
add ax,8
mov yc,ax
cmp ax,word ptr height
jl fin
inc byte ptr pass
mov word ptr yc,4
ret
in2: cmp byte ptr pass,1
jnz in3
add ax,8
mov yc,ax
cmp ax,word ptr height
jl fin
inc byte ptr pass
mov word ptr yc,2
ret
in3: cmp byte ptr pass,2
jnz in4
add ax,4
mov yc,ax
cmp ax,word ptr height
jl fin
inc byte ptr pass
mov word ptr yc,1
ret
in4: add ax,2
mov yc,ax
ret
simple: inc ax
mov yc,ax
fin: ret
incyc endp
;This code replaces READCODE. Pick up a 24-bit chunk from the RASTER
;array and make a code of the necessary size out of it. Cope with files
;larger than 64000 bytes here also
readcode proc near
mov ax,bitoffset
mov dx,bitoffset2
add ax,codesize
adc dx,0
xchg ax,bitoffset
xchg dx,bitoffset2
mov cx,8
div cx
push ax
push ds
lds si,raster
add si,ax
les bx,[si]
mov ax,es
pop ds
mov cx,dx
jcxz noshift
shift: shr al,1
rcr bx,1
loop shift
noshift: and bx,readmask
pop ax
cmp byte ptr nextraster,1
jnz rdone
cmp ah,0f6h
jnz rdone
push bx
mov ax,ds
push ax
lea ax,bitoffset
push ax
call moveup
pop bx
rdone: mov ax,bx
ret
readcode endp
nlzw endp
cseg ends
end nlzw
end